﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright company="Collaboris Ltd." file="SPDocumentRepository.cs">
//   Copyright (c) Collaboris Ltd. All rights Reserved.
// </copyright>
// <summary>
//   The sp document repository.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Collaboris.DataAccess.SharePoint
{
    using System;
    using System.Collections;
    using System.IO;

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;

    /// <summary>
    /// The sp document repository.
    /// </summary>
    /// <typeparam name="T">
    /// </typeparam>
    public abstract class SPDocumentRepository<T> : SPListRepository<T>, ISPDocumentRepository<T>
        where T : DataEntityBase, new()
    {
        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="SPDocumentRepository{T}"/> class. 
        /// Initializes a new instance of the <see cref="SPDocumentRepository{T,C}"/> class. 
        /// Initializes a new instance of the <see cref="SPListRepository{T,C}"/> class. 
        /// Creates a Repository class to access the given list. It's assumed that the given list
        /// is located at the root of the site collection
        /// </summary>
        /// <param name="listName">
        /// </param>
        public SPDocumentRepository(string listName)
            : base(listName)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SPDocumentRepository{T}"/> class. 
        /// Initializes a new instance of the <see cref="SPDocumentRepository{T,C}"/> class. 
        /// Initializes a new instance of the <see cref="SPListRepository{T,C}"/> class. 
        /// Creates a Repository class to access the given list in the given web.
        /// </summary>
        /// <param name="web">
        /// </param>
        /// <param name="listName">
        /// </param>
        public SPDocumentRepository(SPWeb web, string listName)
            : base(web, listName)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SPDocumentRepository{T}"/> class. 
        /// Initializes a new instance of the <see cref="SPDocumentRepository{T,C}"/> class. 
        /// Initializes a new instance of the <see cref="SPListRepository{T,C}"/> class. 
        /// Creates a Repository class to access the given list in the given web.
        /// </summary>
        /// <param name="web">
        /// </param>
        /// <param name="list">
        /// </param>
        public SPDocumentRepository(SPWeb web, SPList list)
            : base(web, list)
        {
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Saves a document in a document library using the given user credentials
        /// </summary>
        /// <param name="businessObject">
        /// </param>
        /// <param name="documentStream">
        /// </param>
        /// <param name="folder">
        /// </param>
        /// <param name="fileName">
        /// </param>
        /// <param name="user">
        /// </param>
        /// <param name="contentTypeName">
        /// The content Type Name.
        /// </param>
        public void SaveDocument(
            T businessObject, Stream documentStream, string folder, string fileName, SPUser user, string contentTypeName)
        {
            // ensure that the list is a document library
            SPDocumentLibrary documentLibrary = this.SharePointList as SPDocumentLibrary;

            if (documentLibrary == null)
            {
                throw new ArgumentException("Cannot save the document.The target list is not a document library");
            }

            // Create an hash table with the metadata from the business object.
            // Hashtable docMetadata = new Hashtable();
            // DataMap(businessObject, ref docMetadata);
            this.Web.AllowUnsafeUpdates = true;

            // Build the server relative path for the folder where the document will be placed
            string documentUrl;

            if (!String.IsNullOrEmpty(folder))
            {
                documentUrl = documentLibrary.RootFolder.Url + SPHttpUtility.UrlPathEncode(folder, false);
            }
            else
            {
                documentUrl = documentLibrary.RootFolder.Url;
            }

            documentUrl = String.Format(@"{0}/{1}/{2}", this.Web.Url, documentUrl, fileName);

            // add the file
            // web.Files.Add(documentUrl, documentStream, docMetadata, true);
            user = this.Web.EnsureUser(user.LoginName);
            SPFile destFile = this.Web.Files.Add(documentUrl, documentStream, user, user, DateTime.Now, DateTime.Now);

            // SPFile destFile = this.web.Files.Add(documentUrl, documentStream, true);
            SPListItem listItem = destFile.Item;
            DataMap(businessObject, ref listItem);

            // added this so that when adding the document for a "Link to a Document" then the content type can be set
            // will also be useful for any instance when multiple content types have been bound to a list
            listItem["Content Type"] = contentTypeName;

            listItem.Update();
        }

        #endregion

        #region Implemented Interfaces

        #region ISPDocumentRepository<T>

        /// <summary>
        /// Returns the document with the given Id
        /// </summary>
        /// <param name="itemId">
        /// The item Id.
        /// </param>
        /// <returns>
        /// </returns>
        public virtual SPFile GetDocument(int itemId)
        {
            SPListItem listItem = this.GetListItem(itemId);

            if (listItem == null)
            {
                return null;
            }

            return listItem.File;
        }

        /// <summary>
        /// Saves a file with the specified metadata in the document library
        /// </summary>
        /// <param name="businessObject">
        /// The business object with the metadata to save
        /// </param>
        /// <param name="documentStream">
        /// The stream with the document content
        /// </param>
        /// <param name="folder">
        /// The list relative path to the folder where the document is to be stored
        /// </param>
        /// <param name="fileName">
        /// </param>
        public virtual void SaveDocument(T businessObject, Stream documentStream, string folder, string fileName)
        {
            // ensure that the list is a document library
            var documentLibrary = this.SharePointList as SPDocumentLibrary;

            if (documentLibrary == null)
            {
                throw new ArgumentException("Cannot save the document.The target list is not a document library");
            }

            // Create an hash table with the metadata from the business object.
            var docMetadata = new Hashtable();
            DataMap(businessObject, ref docMetadata);

            this.Web.AllowUnsafeUpdates = true;

            // Build the server relative path for the folder where the document will be placed
            string documentUrl;

            if (!String.IsNullOrEmpty(folder))
            {
                documentUrl = documentLibrary.RootFolder.ServerRelativeUrl + SPHttpUtility.UrlPathEncode(folder, false);
            }
            else
            {
                documentUrl = documentLibrary.RootFolder.ServerRelativeUrl;
            }

            documentUrl = documentUrl + "/" + fileName;

            // add the file
            this.Web.Files.Add(documentUrl, documentStream, docMetadata, true);
        }

        /// <summary>
        /// Saves a document in a document library using the given user credentials
        /// </summary>
        /// <param name="businessObject">
        /// </param>
        /// <param name="documentStream">
        /// </param>
        /// <param name="folder">
        /// </param>
        /// <param name="fileName">
        /// </param>
        /// <param name="user">
        /// </param>
        public virtual void SaveDocument(
            T businessObject, Stream documentStream, string folder, string fileName, SPUser user)
        {
            // ensure that the list is a document library
            var documentLibrary = this.SharePointList as SPDocumentLibrary;

            if (documentLibrary == null)
            {
                throw new ArgumentException("Cannot save the document.The target list is not a document library");
            }

            // Create an hash table with the metadata from the business object.
            var docMetadata = new Hashtable();
            DataMap(businessObject, ref docMetadata);

            this.Web.AllowUnsafeUpdates = true;

            // Build the server relative path for the folder where the document will be placed
            string documentUrl;

            if (!String.IsNullOrEmpty(folder))
            {
                documentUrl = documentLibrary.RootFolder.ServerRelativeUrl + SPHttpUtility.UrlPathEncode(folder, false);
            }
            else
            {
                documentUrl = documentLibrary.RootFolder.ServerRelativeUrl;
            }

            documentUrl = documentUrl + "/" + fileName;

            // add the file
            // web.Files.Add(documentUrl, documentStream, docMetadata, true);
            SPFile destFile = this.Web.Files.Add(documentUrl, documentStream, user, user, DateTime.Now, DateTime.Now);

            SPListItem listItem = destFile.Item;
            DataMap(businessObject, ref listItem);

            listItem.Update();
        }

        #endregion

        #endregion
    }
}